﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SetupLauncher.Domain.Util;
using SetupLauncher.Domain.Exceptions;

namespace SetupLauncher.Domain.Logic
{
    public class Setup
    {
        private const string CONST_SETUP_CONSOLE = @"{0}\SetupConsole.exe";
        private const string CONST_PARAMETERS_FILE = @"{0}Parameters_v{1}_{2}.xml";
        private const string CONST_SETUP_CONSOLE_ARG_INSTALL = "/i";
        private const string CONST_SETUP_PARAMETERS_FOLDER = @"{0}/Setup/{1}/";
        //private const string CONST_SETUP_CONSOLE_ARG_HIDE = "/hidewizard /hideresult";
        private const string CONST_SETUP_CONSOLE_ARG_HIDE = "";
        private const string CONST_SETUP_CONSOLE_ARG_FILE = "/filename=\"{0}\\{1}\"";

        private const string CONST_SETUP_PARAMETER_PSE = "PSEParameters.xml";
        private const string CONST_SETUP_PARAMETER_PSE_COMPONENTS = "PSEComponentsParameters.xml";

        Logger.ILoggable _log;

        Entity.Product _product;
        Entity.Environment _environment;
        Entity.PerfilType _perfilType;
        Entity.Version _version;

        string _supportFolderExternalSetup;

        TeamSystem _teamSystem;


        public Setup(string supportFolderExternalSetup, Entity.Product product, Entity.Environment environment, Entity.PerfilType perfilType, Entity.Version version, Logger.ILoggable log)
        {
            Initialize(supportFolderExternalSetup, product, environment, perfilType, version, log);
        }

        public Setup(string supportFolderExternalSetup, Entity.Product product, Entity.Environment environment, Entity.PerfilType perfilType, Entity.Version version) 
        {
            Initialize(supportFolderExternalSetup, product, environment, perfilType, version, null);
        }

        private void Initialize(string supportFolderExternalSetup, Entity.Product product, Entity.Environment environment, Entity.PerfilType perfilType, Entity.Version version, Logger.ILoggable log)
        {
            Exceptions.ValidationException exception = new Exceptions.ValidationException();

            if (product == null)
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Produto foi Informado",
                    PropertyName = "product",
                    PropertyTitle = "Produto"
                });

            if (environment == null)
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Ambiente foi Informado",
                    PropertyName = "environment",
                    PropertyTitle = "Ambiente"
                });

            if (version == null)
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhuma Versão foi Informada",
                    PropertyName = "version",
                    PropertyTitle = "Versão"
                });            

            if (exception.CountValidations > 0)
                throw exception;

            _log = log;
            _product = product;
            _environment = environment;
            _perfilType = perfilType;
            _version = version;
            _supportFolderExternalSetup = supportFolderExternalSetup;

            _teamSystem = new TeamSystem(_log);
        }

        public void Execute()
        {
            PrepareEnvironment();

            GetSource();

            string parametersFile = CreateParametersName();

            string folder = GetParametersFile(ref parametersFile);
            ChangeParameters(folder, parametersFile);

            InstallPSE(folder);
            InstallPSEComponents(folder);

            Execute(folder, parametersFile);
        }

        private const string CONST_EXTERNAL_SETUP = @"\ExternalSetup";
        private const string CONST_EXTERNAL_SETUP_PSE = @"PSE";
        private const string CONST_EXTERNAL_SETUP_PSE_COMPONENTS = @"PSEComponents";

        private void InstallPSEComponents(string folder)
        {
            string path = folder + CONST_EXTERNAL_SETUP;

            InstallExternalSetup(path, CONST_EXTERNAL_SETUP_PSE_COMPONENTS, CONST_SETUP_PARAMETER_PSE_COMPONENTS);
        }

        private void InstallPSE(string folder)
        {
            string path = folder + CONST_EXTERNAL_SETUP;

            InstallExternalSetup(path, CONST_EXTERNAL_SETUP_PSE, CONST_SETUP_PARAMETER_PSE);
        }

        private void InstallExternalSetup(string path, string product, string fileParameter)
        {
            string source = _supportFolderExternalSetup + @"\" + fileParameter;
            string destination = path + @"\" + product + @"\" + fileParameter;

            System.IO.File.Copy(source, destination, true);

            Execute(path + @"\" + product, destination);
        }

        public static void ShowManualSetup(string from, string to)
        {
            //try
            //{
            //    TeamSystem teamSystem = new TeamSystem();

            //    teamSystem.DownloadFile(from, to);

            //    string file = string.Format(@"{0}\InstallationGuide.pdf", to);
            //}
            //catch (Exception ex)
            //{
            //}
        }

        private string CreateParametersName()
        {
            string name = string.Format("{0}{1}", _product.Name[0].ToString().ToUpper(), _product.Name.Substring(1).ToLower());
            return string.Format(CONST_PARAMETERS_FILE, name, _product.MajorVersion, GetPerfilName());
        }

        private string GetPerfilName()
        {
            string typeName = "";
            switch (_perfilType)
            {
                case SetupLauncher.Domain.Entity.PerfilType.Desenvolvimento:
                    typeName = "desenv";
                    break;
                case SetupLauncher.Domain.Entity.PerfilType.Teste:
                    typeName = "test";
                    break;
            }
            return typeName;
        }

        private void PrepareEnvironment()
        {
            PrepareEnvironment prepare = new PrepareEnvironment(_log, _product, _environment);
            prepare.Execute();
        }

        private void GetSource()
        {
            _teamSystem.GetSetupSource(_product.Name, _environment.TeamSystemPath, _environment.WorkSpacePath, _version.Path);
        }

        private string GetParametersFile(ref string file)
        {
            WriteLog("Criando os parâmetros para a chamada do setup");
            string path = string.Format(CONST_SETUP_PARAMETERS_FOLDER, _product.TemProject, _environment.Name) + file;

            string tsPath = _version.Path + @"/x86/" + file;
            string workspacePath = _version.Path.Replace(@"$/", _environment.WorkSpacePath + @"/").Replace(@"\", @"/") + "/x86/";

            file = file.Replace("_" + GetPerfilName(), string.Empty);
            
            _teamSystem.GetParametersSource(path, workspacePath + file);
            
            return workspacePath;
        }

        private void ChangeParameters(string folderParameters, string parametersFile)
        {
            string parameterPath = string.Format(@"{0}/{1}", folderParameters, parametersFile);
            string configPath = string.Format(@"{0}/SetupConfiguration.xml", folderParameters);

            CreateParameter productParameter = new CreateParameter(parameterPath, configPath, _product, _environment, _version, _log);
            productParameter.AlterConfiguration();
            productParameter.AlterParameter();
        }

        private void Execute(string folder, string parametersFile)
        {
            string args = string.Empty;
            if(string.IsNullOrEmpty(parametersFile))
                args = CreateArgs(_environment.WorkSpacePath);
            else
                args = CreateArgs(folder, parametersFile);

            string file = string.Format(CONST_SETUP_CONSOLE, folder);
            WriteLog(string.Format("Setup: {0}{1}", file, args));
            ExecuteProgram.Run(file, args);
        }

        private string CreateArgs(string setupPath, string parametersFile)
        {
            string file = string.Format(CONST_SETUP_CONSOLE_ARG_FILE, setupPath, parametersFile);
            return string.Format(" {0} {1} {2}", CONST_SETUP_CONSOLE_ARG_INSTALL, file, CONST_SETUP_CONSOLE_ARG_HIDE);
        }

        private string CreateArgs(string setupPath)
        {
            return string.Format(" {0} {1} ", CONST_SETUP_CONSOLE_ARG_INSTALL, CONST_SETUP_CONSOLE_ARG_HIDE);
        }

        protected void WriteLog(string message)
        {
            if (_log == null)
                return;
            _log.Write(message);
        }

        protected void WriteException(string message)
        {
            if (_log == null)
                return;
            _log.WriteException(message);
        }
    }
}
